home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / GXEdit Library & Doc / GXEditLine.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-10  |  17.5 KB  |  729 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:                GXEditLine.c
  3.     
  4.     Contains:
  5.     
  6.     Written by:        Barton R. House
  7.     
  8.     Copyright:        © 1993 by Apple Computer, Inc., All rights reserved.
  9.     
  10. */
  11.  
  12. #include "GXEdit.h"
  13. #include "GXEditDebug.h"
  14. #include "GXEditDoc.h"
  15. #include "GXEditLine.h"
  16. #include "GXEditNewRun.h"
  17. #include "GXEditStyle.h"
  18. #include "GXEditSelection.h"
  19. #include "GXEditError.h"
  20.  
  21. #include "graphics routines.h"
  22. #include "math routines.h"
  23. #include "graphics libraries.h"
  24. #include "layout routines.h"
  25. #include "selection library.h"
  26.  
  27. #define MIN(x,y) ((x) < (y) ? (x) : (y))
  28. #define MAX(x,y) ((x) > (y) ? (x) : (y))
  29.  
  30. static void        CalcLayout(DocPtr dp, ParaPtr pp, LinePtr lp);                                                          
  31. static void        CalcOffsets(DocPtr dp, LinePtr lp, short runIndex);
  32. static void        CalcHeight(DocPtr dp, LinePtr lp);
  33. static void         DrawHighlight(DocPtr dp, gxShape layout, short startOffset, short endOffset);
  34. static void        DrawCaret(DocPtr dp, gxShape layout, short offset);
  35. static short         GetPreviousOffset(LinePtr lp, short lineOffset);
  36.  
  37. /* insert text into the gxLine */
  38.  
  39. void InsertDocLineText(DocPtr dp, LinePtr lp, short lineOffset, short numText)
  40. {
  41.     #pragma unused(pp)
  42.     if(lineOffset < 0 || lineOffset > lp->numText)
  43.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  44.             
  45.     lp->numText += numText;    
  46.     lp->dirty = true;
  47.                 
  48. }
  49.  
  50.  
  51. /* join the two lines disposing of the right gxLine data structures */
  52.  
  53. void JoinDocLines(LinePtr left, LinePtr right)
  54. {
  55.     #pragma unused(dp)
  56.     #pragma unused(pp)
  57.     left->numText += right->numText;
  58.     left->dirty = true;
  59.     
  60.     if(right->layout != nil)
  61.         GXDisposeShape(right->layout);
  62.     
  63. }
  64.  
  65. void SplitDocLine(DocPtr dp, LinePtr lp, short lineOffset, LinePtr newLine)
  66. {
  67.     #pragma unused(pp)
  68.     if(lineOffset < 0 || lineOffset > lp->numText)
  69.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  70.     
  71.     lp->dirty = true;
  72.     
  73.     newLine->dirty = true;
  74.     newLine->layout = nil;
  75.         
  76.     newLine->numText = lp->numText - lineOffset;
  77.     lp->numText = lineOffset;
  78.     
  79. }
  80.  
  81. /* the gxLine is our basic drawing unit */
  82.                                  
  83. void DrawDocLine(DocPtr dp, ParaPtr pp, LinePtr lp)
  84. {
  85.     Rect            rect;
  86.     long            docOffset;
  87.     long            startOffset;
  88.     long            endOffset;
  89.     gxPoint            textPosition;
  90.     gxRectangle        aRect;
  91.     gxShape            clip;
  92.     Boolean            drawLine;
  93.     Boolean            drawSelection;
  94.     Boolean            clearSelection;
  95.     SelPtr            sp;
  96.     Boolean            startAtEnd;
  97.     Boolean            endAtStart;
  98.     Boolean            isCaret;
  99.     
  100.     drawLine = !(dp->drawn & pp->drawn & lp->drawn);
  101.     
  102.     /* see if this gxLine is selected and needs to be drawn */
  103.     
  104.     sp = &dp->selection;
  105.     
  106.     docOffset = pp->docOffset + lp->paraOffset;
  107.     endOffset = docOffset + lp->numText;
  108.     
  109.     startAtEnd = (sp->startDocOffset == endOffset);
  110.     endAtStart = (sp->endDocOffset == docOffset);
  111.     isCaret = (sp->endDocOffset == sp->startDocOffset);
  112.         
  113.     if(docOffset <= sp->endDocOffset && endOffset >= sp->startDocOffset &&
  114.       !(isCaret && ((sp->endOfLine && endAtStart) || (!sp->endOfLine && startAtEnd))) &&
  115.       !(!isCaret && (endAtStart || startAtEnd))) {
  116.     
  117.            /* this gxLine falls in the selection range */
  118.        
  119.            if(docOffset > dp->selection.startDocOffset)
  120.                startOffset = docOffset;
  121.            else
  122.                startOffset =  dp->selection.startDocOffset;
  123.        
  124.            if(docOffset + lp->numText < dp->selection.endDocOffset)
  125.                endOffset = docOffset + lp->numText;
  126.            else
  127.                endOffset =  dp->selection.endDocOffset;
  128.                
  129.            startOffset -= docOffset;
  130.            endOffset -= docOffset;
  131.                                      
  132.            if(lp->selected)
  133.                if(lp->startOffset != startOffset || lp->endOffset != endOffset)
  134.                    drawSelection = true;
  135.                else
  136.                    drawSelection = false;
  137.            else
  138.                drawSelection = true;
  139.                       
  140.         drawSelection |= drawLine;
  141.         
  142.         clearSelection = false;
  143.         
  144.     } else {
  145.     
  146.         if(lp->selected && !drawLine)
  147.             clearSelection = true;
  148.         else
  149.             clearSelection = false;
  150.     
  151.         drawSelection = false;
  152.             
  153.     }
  154.     
  155.     if(!(drawLine || drawSelection || clearSelection))
  156.         return;
  157.     
  158.     if(lp->dirty)
  159.         CalcLayout(dp, pp, lp);
  160.  
  161.     /* set the correct clip */
  162.     
  163.     if(dp->verticalText) {
  164.     
  165.         rect.right = dp->viewRect.right - (pp->start + lp->start - dp->top);
  166.         rect.left = rect.right - lp->height;
  167.         
  168.         rect.top = dp->viewRect.top;
  169.         
  170.         if(rect.left < dp->viewRect.left)
  171.             rect.left = dp->viewRect.left;
  172.     
  173.         rect.bottom = dp->viewRect.bottom;
  174.     
  175.         if(rect.right > dp->viewRect.right)
  176.             rect.right = dp->viewRect.right;
  177.         
  178.     } else {
  179.     
  180.         rect.top = dp->viewRect.top + pp->start + lp->start - dp->top;
  181.         rect.bottom = rect.top + lp->height;
  182.  
  183.         if(rect.top < dp->viewRect.top)
  184.             rect.top = dp->viewRect.top;
  185.             
  186.         rect.left = dp->viewRect.left;
  187.         
  188.         if(rect.bottom > dp->viewRect.bottom)
  189.             rect.bottom = dp->viewRect.bottom;
  190.         
  191.         rect.right = dp->viewRect.right;
  192.         
  193.     }
  194.     
  195.     aRect.top = ff(rect.top);
  196.     aRect.left = ff(rect.left);
  197.     aRect.bottom = ff(rect.bottom);
  198.     aRect.right = ff(rect.right);
  199.     
  200.     clip = GXNewRectangle(&aRect);
  201.  
  202.     /* This ignore is needed because we do not keep track of the current
  203.           clip of the view port.  Thus, we will often set the clip to the same rect
  204.           which generates a notice*/
  205.  
  206. #ifdef debugging
  207.     GXIgnoreGraphicsNotice(clip_already_set);
  208. #endif
  209.  
  210.     GXSetViewPortClip(dp->docViewPort, clip);
  211.     
  212. #ifdef debugging
  213.     GXPopGraphicsNotice();
  214. #endif
  215.     
  216.     /* make sure the layout is at the right position */
  217.     
  218.     if(dp->verticalText) {
  219.         textPosition.x = ff(dp->viewRect.right - (pp->start + lp->start - dp->top + lp->ascent));
  220.         textPosition.y = ff(dp->viewRect.top + dp->leftMargin);
  221.     } else {
  222.         textPosition.x = ff(dp->viewRect.left + dp->leftMargin);
  223.         textPosition.y = ff(dp->viewRect.top + pp->start + lp->start - dp->top + lp->ascent);
  224.     }
  225.     
  226.     if(textPosition.x != lp->layoutPos.x || textPosition.y != lp->layoutPos.y) {
  227.         GXMoveShapeTo(lp->layout, textPosition.x, textPosition.y);
  228.         lp->layoutPos = textPosition;
  229.     }
  230.  
  231.     if(drawLine) {
  232.  
  233.         
  234.         /* erase the gxLine */
  235.     
  236.         SetShapeCommonColor(clip, gxWhite);
  237.         GXSetShapeViewPorts(clip, 1, &dp->offscreenPort);
  238.         GXDrawShape(clip);
  239.         
  240.         if(lp->numText == 0)
  241.             return;                /* nothing to draw or select */
  242.  
  243.         /* now draw the layout */
  244.         
  245.         GXDrawShape(lp->layout);
  246.  
  247.         /* now draw the gxBitmap to the screen */
  248.         
  249.         GXSetShapeViewPorts(dp->offscreenBitmap, 1, &dp->docViewPort);
  250.         GXDrawShape(dp->offscreenBitmap);
  251.         GXSetShapeViewPorts(dp->offscreenBitmap, 1, &dp->offscreenPort);
  252.         
  253.         lp->drawn = true;
  254.         lp->selected = false;
  255.         
  256.         /* check to see if we drawn in the bottom cleared area */
  257.         
  258.         if(dp->verticalText) {
  259.             if(dp->bottomClear < rect.left)
  260.                 dp->bottomClear = rect.left;
  261.         } else{
  262.              if(dp->bottomClear < rect.bottom)
  263.                 dp->bottomClear = rect.bottom;
  264.         }
  265.         
  266.     }
  267.         
  268.     if(drawSelection) {
  269.                 
  270.         if(lp->selected && (lp->startOffset == lp->endOffset)) {
  271.         
  272.             DrawCaret(dp, lp->layout, lp->startOffset);
  273.             lp->selected = false;
  274.             
  275.         }
  276.                 
  277.         if(startOffset == endOffset) {
  278.         
  279.             if(lp->selected)
  280.                 DrawHighlight(dp, lp->layout, lp->startOffset, lp->endOffset);
  281.     
  282.             DrawCaret(dp, lp->layout, startOffset);
  283.             
  284.             
  285.         } else {
  286.         
  287.             if(lp->selected) {
  288.             
  289.             
  290.                 /*                     |--------------|                                */
  291.                 /*        |----|                                        case 0            */
  292.                 /*                                        |---|        case 1            */
  293.                 /*                |-----|                                case 2            */
  294.                 /*                                |-----|                case 3            */
  295.                 /*                        |----|                        case 4            */
  296.                 /*                |----------------------|            case 5            */
  297.                 
  298.             
  299.                 if(startOffset < lp->startOffset) {
  300.                 
  301.                     if(endOffset > lp->endOffset) {
  302.                     
  303.                         /* case 5 */
  304.                         
  305.                         DrawHighlight(dp, lp->layout, startOffset, lp->startOffset);
  306.                         DrawHighlight(dp, lp->layout, lp->endOffset, endOffset);
  307.                         
  308.                     } else if(endOffset > lp->startOffset) {
  309.                     
  310.                         /* case 2 */
  311.                     
  312.                         DrawHighlight(dp, lp->layout, startOffset, lp->startOffset);
  313.                         DrawHighlight(dp, lp->layout, endOffset, lp->endOffset);
  314.                         
  315.                     } else {
  316.                     
  317.                         /* case 0 */
  318.                     
  319.                         DrawHighlight(dp, lp->layout, lp->startOffset, lp->endOffset);
  320.                         DrawHighlight(dp, lp->layout, startOffset, endOffset);
  321.                         
  322.                     }
  323.                 
  324.                 } else {
  325.                 
  326.                     if(startOffset > lp->endOffset) {
  327.                     
  328.                         /* case 1 */
  329.                         
  330.                         DrawHighlight(dp, lp->layout, lp->startOffset, lp->endOffset);
  331.                         DrawHighlight(dp, lp->layout, startOffset, lp->endOffset);
  332.                         
  333.                     } else if(endOffset < lp->endOffset) {
  334.                     
  335.                         /* case 4 */
  336.                         
  337.                         DrawHighlight(dp, lp->layout, lp->startOffset, startOffset);
  338.                         DrawHighlight(dp, lp->layout, endOffset, lp->endOffset);
  339.                         
  340.                     } else {
  341.                     
  342.                         /* case 3 */
  343.                     
  344.                         DrawHighlight(dp, lp->layout, lp->startOffset, startOffset);
  345.                         DrawHighlight(dp, lp->layout, lp->endOffset, endOffset);
  346.                     }
  347.                     
  348.                 }
  349.  
  350.             } else
  351.                 DrawHighlight(dp, lp->layout, startOffset, endOffset);
  352.         
  353.         }
  354.         
  355.         lp->selected = true;
  356.         lp->startOffset = startOffset;
  357.         lp->endOffset = endOffset;
  358.         
  359.     } else if(clearSelection) {
  360.                 
  361.             if(lp->startOffset == lp->endOffset)
  362.                 DrawCaret(dp, lp->layout, lp->startOffset);
  363.             else
  364.                 DrawHighlight(dp, lp->layout, lp->startOffset, lp->endOffset);
  365.     
  366.             lp->selected = false;
  367.     }
  368.     
  369.     GXDisposeShape(clip);
  370.         
  371. }
  372.  
  373. void NewDocLine(LinePtr lp)
  374. {
  375.     #pragma unused(dp)
  376.     #pragma unused(pp)
  377.  
  378.     lp->layout = nil;
  379.     lp->paraOffset = 0;
  380.     lp->numText = 0;
  381.     lp->start = 0;
  382.     lp->reflow = false;
  383.     lp->drawn = false;
  384.     lp->selected = false;
  385.     lp->dirty = true;
  386.         
  387. }
  388.  
  389. short HitTestDocLine(DocPtr dp, ParaPtr pp, LinePtr lp, Point where)
  390. {
  391.     short            lineOffset;
  392.     gxLayoutHitInfo    hitInfo;
  393.     gxPoint            hitDown;
  394.     
  395.     if(dp->verticalText) {
  396.         if(where.v <= 0)
  397.             return(0);
  398.     } else {
  399.         if(where.h <= 0)
  400.             return(0);
  401.     }
  402.         
  403.     if(lp->dirty)
  404.         CalcLayout(dp, pp, lp);
  405.     
  406.     hitDown.x = ff(where.h) + lp->layoutPos.x;
  407.     hitDown.y = ff(where.v) + lp->layoutPos.y;
  408.     
  409.     lineOffset = GXHitTestLayout((gxShape) lp->layout, &hitDown, gxHighlightStraight, &hitInfo, nil);
  410.             
  411.     return(lineOffset);
  412.     
  413. }
  414.  
  415. void DocLinePosition(LinePtr lp, long * start, long * end)
  416. {
  417.     /* currently not fully supported */
  418.     #pragma unused(lineOffset)
  419.  
  420.     *start = 0;
  421.     *end = lp->height;            
  422. }
  423.  
  424. short GetLineOffset(DocPtr dp, ParaPtr pp, LinePtr lp, short offsetType, short lineOffset)
  425. {
  426.     if(lp->dirty)
  427.         CalcLayout(dp, pp, lp);
  428.         
  429.     switch(offsetType) {
  430.     case kPreviousOffset:
  431.         return(GetPreviousOffset(lp, lineOffset));
  432.     case kVisualRightOffset:
  433.         return(GXGetRightVisualOffset(lp->layout, lineOffset));
  434.     case kVisualLeftOffset:
  435.         return(GXGetLeftVisualOffset(lp->layout, lineOffset));
  436.     case kDownOffset:
  437.     case kUpOffset:    
  438.     default:
  439.         /* ??? */
  440.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  441.         break;
  442.     }
  443.     
  444. }
  445.  
  446. static short GetPreviousOffset(LinePtr lp, short lineOffset)
  447. {
  448.     unsigned short             firstGlyph, secondGlyph;
  449.     gxLayoutOffsetState        offsetState;
  450.     static SelectionOffset    offsetStateSizes[] = {1, 1, 2, 2, 0};
  451.  
  452.     GXGetOffsetGlyphs(lp->layout, lineOffset, 0, &offsetState, &firstGlyph, &secondGlyph);
  453.     
  454.     return(lineOffset - offsetStateSizes[offsetState & ~gxOffsetInsideLigature]);
  455. }
  456.  
  457. void DocLineClear(DocPtr dp, LinePtr lp, short lineOffset, short numText)
  458. {
  459.     #pragma unused(pp)
  460.  
  461.     if(numText == 0)
  462.         return;
  463.  
  464.     if(lineOffset < 0 || lineOffset > lp->numText)
  465.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  466.         
  467.     if((lineOffset + numText) > lp->numText)
  468.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  469.         
  470.     lp->numText -= numText;
  471.     lp->dirty = true;
  472.         
  473. }
  474.  
  475. void DisposeDocLine(LinePtr lp)
  476. {
  477.     
  478.     if(lp->layout)
  479.         GXDisposeShape(lp->layout);
  480.     
  481. }
  482.  
  483. short GetLineHeight(DocPtr dp, ParaPtr pp, LinePtr lp)
  484. {
  485.     if(lp->dirty)
  486.         CalcLayout(dp, pp, lp);
  487.         
  488.     return(lp->height);
  489. }
  490.  
  491. static void CalcLayout(DocPtr dp, ParaPtr pp, LinePtr lp)
  492. {
  493.     long                textRunCount;
  494.     short            * textRunLengths;
  495.     void                ** textPtrs;
  496.     long                styleRunCount;
  497.     short            * styleRunLengths;
  498.     gxStyle            * styles;
  499.     NewRunPtr        rp;
  500.     short            runIndex;
  501.     gxLayoutOptions    options;
  502.     short            lineText;
  503.     short            runText;
  504.     short            maxRunCount;
  505.     short            startRunIndex;
  506.     short            runOffset;
  507.     short            i;
  508.     StylePtr            sp;
  509.     char                spaceChar = ' ';
  510.     Boolean            spaceSubstitution = false;
  511.     
  512.     if(lp->numText == 0) {
  513.     
  514.         /* really should create an empty gxShape and set gxLine values accordingly */
  515.         /* but for speed -- we will just return for now */
  516.         /* this should not be a problem */
  517.         
  518.         return;
  519.     }
  520.     
  521.     HLock((Handle) pp->runs);
  522.  
  523.     if(lp->layout != nil)
  524.         GXDisposeShape(lp->layout);
  525.     
  526.     maxRunCount = pp->numRuns + 1;        /* +1 incase we need to stuff in a space in place of '\r' */
  527.     
  528.     textRunLengths = (short *) NewPtr(maxRunCount * sizeof(short));
  529.     textPtrs = (void **) NewPtr(maxRunCount * sizeof(void *));
  530.     styles = (gxStyle *) NewPtr(maxRunCount * sizeof(gxStyle));
  531.     
  532.     GetNewRunIndexAndOffset(dp, pp, lp->paraOffset, &startRunIndex, &runOffset);
  533.     lineText = lp->numText;
  534.     textRunCount = 0;
  535.     
  536.     runIndex = startRunIndex;
  537.     rp = *pp->runs + runIndex;
  538.     for(; runIndex < (maxRunCount - 1) && lineText > 0; runIndex++, rp++, lineText -= runText) {
  539.         
  540.         runText = (rp->numText - runOffset > lineText ? lineText : rp->numText - runOffset);
  541.         textRunLengths[textRunCount] = runText;
  542.  
  543.         HLock((Handle) rp->text);
  544.         
  545.         if(textRunLengths[textRunCount] == 0) {
  546.             gxEditPostError(dp, gx_edit_warning);
  547.             continue;
  548.         }
  549.         
  550.         sp =  GetDocStyle(dp, rp->styleIndex);
  551.         
  552.         styles[textRunCount] = sp->textStyle;
  553.         
  554.         textPtrs[textRunCount] = (Ptr) *rp->text + runOffset;
  555.         
  556.         if(runIndex == (pp->numRuns - 1) &&  runText == (rp->numText - runOffset)) {
  557.         
  558.             /* end of paragraph -- should always be '\r' and never gxGlyphPlatform platform type */
  559.             
  560.             if(sp->platform == gxGlyphPlatform)
  561.                 gxEditPostError(dp, gx_edit_internal_fatal_error);
  562.             
  563.             if((((char **) textPtrs)[textRunCount])[runText-1] != '\r')
  564.                 gxEditPostError(dp, gx_edit_internal_fatal_error);
  565.             
  566.             textRunLengths[textRunCount] -= sizeof(char);
  567.             
  568.             /* don't count this run if no text in it -- GX can't handle empty style runs */
  569.             
  570.             if(textRunLengths[textRunCount] != 0)
  571.                 textRunCount++;
  572.             else
  573.                 HUnlock((Handle) rp->text);
  574.             
  575.             textRunLengths[textRunCount] = sizeof(char);
  576.             textPtrs[textRunCount] = (Ptr) &spaceChar;
  577.             
  578.             styles[textRunCount] = sp->textStyle;
  579.             
  580.             spaceSubstitution = true;
  581.         }
  582.         
  583.         textRunCount++;
  584.         runOffset = 0;
  585.         
  586.     }
  587.     
  588.     if(lineText > 0)
  589.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  590.     
  591.     styleRunCount = textRunCount;
  592.     styleRunLengths = textRunLengths;
  593.     
  594.     /* setup layout options */
  595.     
  596.     options = pp->layoutOptions;
  597.     
  598.     /* turn off justification if last gxLine in paragraph */
  599.     
  600.     if(options.just != gxNoJustification &&
  601.        StripAddress(lp) == StripAddress((*pp->lines + pp->numLines - 1)))
  602.         options.just = gxNoJustification;
  603.         
  604.     /* these values may be totally wrong, but they might be right.  If they are right, it
  605.        will save us from having to move it later. And thus, save us from throwing away caches */
  606.  
  607.     if(dp->verticalText) {
  608.         lp->layoutPos.x = ff(dp->viewRect.right - (pp->start + lp->start - dp->top + lp->ascent));
  609.         lp->layoutPos.y = ff(dp->viewRect.top + dp->leftMargin);
  610.     } else {
  611.         lp->layoutPos.x = ff(dp->viewRect.left + dp->leftMargin);
  612.         lp->layoutPos.y = ff(dp->viewRect.top + pp->start + lp->start - dp->top + lp->ascent);
  613.     }
  614.     
  615.  
  616.     if (textRunCount)
  617.         lp->layout = (void *) GXNewLayout(textRunCount, textRunLengths, (void *) textPtrs,
  618.                                 styleRunCount, styleRunLengths, styles, 0, nil, nil,
  619.                                 &options, nil);
  620.     else
  621.         lp->layout = (void *) GXNewLayout(0, nil, nil, 0, nil, nil, 0, nil, nil, &options, nil);
  622.                                 
  623.     GXSetShapeViewPorts(lp->layout, 1, &dp->offscreenPort);
  624.                                 
  625.     GXMoveShapeTo(lp->layout, lp->layoutPos.x, lp->layoutPos.y);
  626.     
  627.     if(dp->verticalText)
  628.         GXRotateShape(lp->layout, ff(90), lp->layoutPos.x, lp->layoutPos.y);
  629.  
  630.     if(spaceSubstitution)
  631.         textRunCount--;
  632.     
  633.     rp = *pp->runs + startRunIndex;
  634.     
  635.     for(i = 0; i < textRunCount; i++, rp++)
  636.         HUnlock((Handle) rp->text);
  637.         
  638.     DisposePtr((Ptr) textRunLengths);
  639.     DisposePtr((Ptr) textPtrs);
  640.     DisposePtr((Ptr) styles);
  641.         
  642.     CalcHeight(dp, lp);
  643.     
  644.     lp->drawn = false;        /* this gxLine needs be redrawn */
  645.     lp->dirty = false;        /* no longer dirty */
  646.     
  647.     HUnlock((Handle) pp->runs);
  648. }
  649.  
  650. #define adjustLineHeightForTallAndLowGlyphs        /* undefine this to show the 'true' ascent and descent */
  651.  
  652. static void CalcHeight(DocPtr dp, LinePtr lp)
  653. {
  654.     fixed        lineAscent;
  655.     fixed        lineDescent;
  656.     
  657.     if(lp->numText == 0) {
  658.     
  659.         lp->ascent = lp->descent = lp->height = 0;
  660.         return;
  661.         
  662.     }
  663.     
  664.     GXGetLayoutSpan((gxShape) lp->layout, &lineAscent, &lineDescent);
  665.     
  666. #ifdef adjustLineHeightForTallAndLowGlyphs
  667.     {
  668.         fixed            boundsAscent, boundsDescent;
  669.         gxRectangle    bounds;
  670.  
  671.         GXGetShapeLocalBounds((gxShape) lp->layout, &bounds);
  672.         boundsAscent = lp->layoutPos.y - bounds.top;
  673.         boundsDescent = bounds.bottom - lp->layoutPos.y;
  674.         
  675.         /* the test for verticalText is temporary */
  676.         
  677.         if(!dp->verticalText && (boundsAscent > lineAscent || boundsDescent > lineDescent)) {
  678.         
  679.             lineAscent = lineAscent > boundsAscent ? lineAscent : boundsAscent;
  680.             lineDescent = lineDescent > boundsDescent ? lineDescent : boundsDescent;
  681.             
  682.             GXSetLayoutSpan(lp->layout, lineAscent, lineDescent);
  683.         }
  684.     }
  685. #endif
  686.     
  687.     lp->ascent = FixedToInt(lineAscent);
  688.     lp->descent = FixedToInt(lineDescent);
  689.  
  690.     lp->height = lp->ascent + lp->descent;    
  691.     
  692. }
  693.  
  694. static void DrawHighlight(DocPtr dp, gxShape layout, short startOffset, short endOffset)
  695. {
  696.     gxShape        highlight;
  697.     
  698.     if(startOffset == endOffset)
  699.         return;        /* no highlight */
  700.     
  701.      highlight = GXGetLayoutHighlight(layout, startOffset, endOffset, gxHighlightAverageAngle, nil);
  702.                                             
  703.     SetShapeCommonTransfer(highlight, gxHighlightMode);
  704.     SetShapeCommonColor(highlight, gxWhite);
  705.     GXSetShapeViewPorts(highlight, 1, &dp->docViewPort);
  706.                                            
  707.     GXDrawShape(highlight);
  708.         
  709.      GXDisposeShape(highlight);
  710.             
  711. }
  712.  
  713. static void DrawCaret(DocPtr dp, gxShape layout, short offset)
  714. {
  715.     gxShape        caret;
  716.     
  717.     caret = GXGetLayoutCaret(layout, offset, gxHighlightAverageAngle, gxSplitCaretType, nil);
  718.  
  719.     SetShapeCommonTransfer(caret, gxXorMode);
  720.     SetShapeCommonColor(caret, gxWhite);
  721.     GXSetShapeViewPorts(caret, 1, &dp->docViewPort);
  722.      
  723.      GXDrawShape(caret);
  724.         
  725.     GXDisposeShape(caret);
  726.     
  727. }
  728.  
  729.